% !TEX program = XeLaTeX
% !TEX encoding = UTF-8
\documentclass[UTF8,nofonts]{ctexart}
\setCJKmainfont[BoldFont=STHeiti,ItalicFont=STKaiti]{STSong}
\setCJKsansfont[BoldFont=STHeiti]{STXihei}
\setCJKmonofont{STFangsong}

\begin{document}

%daveti: translated on Jan 1, 2017
%NOTE: above is needed for MacTex.

\subsection{数值系统 Numeral systems}

因为每个人都有10个手指，所以十进制数值系统一直都是我们的默认。
实际上，和其他进制相比，十进制在科学和数学范畴内并没有特比的地方。
数字电路系统使用二进制：0表示开路（导线中没有电流），1表示闭路。
例如，10在二进制里是2，100是4，等等。

如果该数值系统有10个不同的数字，那么10就是权值\IT{radix}或者基本值\IT{radix}。
二进制系统的权值\IT{radix}是2。

值得复习一下的要点：
1) \IT{数 number}是一个数, 而\IT{数字字面值 digit}是用来在某进制系统中书写数用的，通常是一个字符；
2) 数的大小在不同的进制中是不变的：变的是书写的形式。

如何在不同进制中转换某一个数呢？

其根本是根据数字字面值的位置标注来确定权重和转换。也就是说，一个数字字面值出现在该数的不同位置具有不同的权重。
在十进制中如果2出现在数字最右边，那就是2。
如果这个2是从右边数第二个数字，那就是20。

那么$1234$代表什么意义呢？

$10^3 \cdot 1 + 10^2 \cdot 2 + 10^1 \cdot 3 + 1 \cdot 4$ = 1234 or 
$1000 \cdot 1 + 100 \cdot 2 + 10 \cdot 3 + 4 = 1234$

和十进制一样，二进制也是如此，只不过其基本值成了2，而不是10。
让我们看一看二进制0b101011的意义？

$2^5 \cdot 1 + 2^4 \cdot 0 + 2^3 \cdot 1 + 2^2 \cdot 0 + 2^1 \cdot 1 + 2^0 \cdot 1 = 43$ or
$32 \cdot 1 + 16 \cdot 0 + 8 \cdot 1 + 4 \cdot 0 + 2 \cdot 1 + 1 = 43$

和位置标注不同的就是非位置标注，例如罗马数字系统。
\footnote{关于数字系统的演进, 参看\InSqBrackets{\TAOCPvolII{}, 195--213.}}。
可能人类之所以倾向于使用位置标注是因为在纸上运算加法乘法等基本运算更容易。

事实上，二进制数字和我们一直用的十进制一样，可以加减乘除，只不过只有2个数字字面值可以使用。

二进制在源代码书写或者显示的时候有些冗长，所以十六进制由此而生。
十六进制的字面值包括0..9和6个拉丁字符：A..F。
每个十六进制数字字面值相当于4比特位或者4个二进制数字字面值，所以在二进制和十六进制之间转换很容易，心算就行。


\begin{center}
\begin{longtable}{ | l | l | l | }
\hline
\HeaderColor 十六进制 hexadecimal & \HeaderColor 二进制 binary & \HeaderColor 十进制 decimal \\
\hline
0	&0000	&0 \\
1	&0001	&1 \\
2	&0010	&2 \\
3	&0011	&3 \\
4	&0100	&4 \\
5	&0101	&5 \\
6	&0110	&6 \\
7	&0111	&7 \\
8	&1000	&8 \\
9	&1001	&9 \\
A	&1010	&10 \\
B	&1011	&11 \\
C	&1100	&12 \\
D	&1101	&13 \\
E	&1110	&14 \\
F	&1111	&15 \\
\hline
\end{longtable}
\end{center}

如何确定某个数字使用何种进制？

十进制数字一般正常书写，例如1234。但是某些汇编器也支持显示使用十进制标注，然后数字后面通常加一个"d''后缀，例如：1234d。

二进制数字通常有前缀"0b": 0b100110111 (\ac{GCC}支持另一种非语言标准的标注扩展\footnote{\url{https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html})}。
另一种表示方式是后缀"b"， 例如：100110111b。
本书试图坚持使用"0b"前缀表达形式来书写二进制数字。

十六进制数字在\CCpp和其他编程语言\ac{PL}中一般带有前缀"0x": 0x1234ABCD。
或者使用"h"后缀：1234ABCDh。这种后缀写法通常出现在汇编器和调试器中。
如果该数字以A...F打头，"0"通常被当作额外前缀：0ABCDEFh。
% TBT
本书试图坚持使用"0x"前缀表达形式来书写十六进制数字。

是否要学习心算转化不同进制数字呢？上表提供了1-16在不同进制中的表达形式，而且比较容易记住。
对于大些的数字，不推荐死记硬背这些转换。

或许，对大家来说最显而易见的十六进制数字出现在\ac{URL}中，因为非拉丁字符通常用十六进制数字来表达。例如：
\url{https://en.wiktionary.org/wiki/na\%C3\%AFvet\%C3\%A9}这个\ac{URL}关于\q{naÃ¯vetÃ©}这个单词的文章。

\subsubsection{八进制 Octal radix}

另一个在以前的计算机编程中常用的就是八进制：8个字面值(0..7)， 每个数字相当于3个比特，所以在八进制和二进制之间转换很容易。
虽然八进制基本被十六进制所取代，但是一个大家经常使用的*NIX工具依然把八进制数字作为其输入参数：\TT{chmod}。

\myindex{UNIX!chmod}
如许多*NIX用户已经了解的，\TT{chmod}的参数是一个3位数的数字。从左边数第一个数字是文件属主的权限，第二个是文件所属的组权限，第三个是其他所有人的权限。
其中每位数字又可以用二进制来表示：

\begin{center}
\begin{longtable}{ | l | l | l | }
\hline
\HeaderColor 十进制 decimal & \HeaderColor 二进制 binary & \HeaderColor 含义 meaning \\
\hline
7	&111	&\textbf{rwx} \\
6	&110	&\textbf{rw-} \\
5	&101	&\textbf{r-x} \\
4	&100	&\textbf{r-{}-} \\
3	&011	&\textbf{-wx} \\
2	&010	&\textbf{-w-} \\
1	&001	&\textbf{-{}-x} \\
0	&000	&\textbf{-{}-{}-} \\
\hline
\end{longtable}
\end{center}

由此而见，二进制形式中的每一个bit代表一种权限：读／写／执行 (read/write/execute)。

而我为什么讨论\TT{chmod}的原因就是其参数可以用八进制数字来表示。
例如，644。
当你运行\TT{chmod 644 file}，你设置了读／写权限给文件属主，读权限给组用户，读权限给其他人。
把644这个八进制数字转换成二进制，即\TT{110100100}，或者用3个bit一组来间隔开成3组，\TT{110 100 100}。

现在我们就能清楚看到每个组代表相应的属主／组／其他人(owner/group/others)的权限：第一个是\TT{rw-}，第二个是\TT{r--}，第三个是\TT{r--}。

八进制在一些老机器中，例如PDP-8中很流行，因为一个机器字可以是12，24或者36位，而这些数字都可以被3整除，所以八进制表示方法在这些系统上很自然。
现在的机器一般使用16，32或者64位机器字（地址总线长度），而这些数字被4整除，所以十六进制更方便。

所有的标准\CCpp编译器支持八进制数字系统。
这有时候会引起混淆，因为八进制数字通常带有"0"作为前缀，例如，0377就是十进制的255。
当你在拼写中忘了前缀"0"，例如写成了"9"而不是"09"，编译器会报错。
例如，GCC可能报如下错误：\\
\TT{error: invalid digit "9" in octal constant}.

% TBT

\subsubsection{整除性 Divisibility}

When you see a decimal number like 120, you can quickly deduce that it's divisible by 10, because the last digit is zero.
In the same way, 123400 is divisible by 100, because two last digits are zeros.
当你看到一个十进制数字，例如120，你立马就知道这个数字可以被10整除，因为120的最后一位是0。
同样，123400可以被100整除，因为最后两位数字都是0。

类似的，十六进制数字0x1230被0x10 (16)整除，0x123000被0x1000 (4096)整除，等等。

而二进制数字0b1000101000被0b1000 (8)整除，等等。

依靠这个特性，我们可以很快辨别出一个内存区域大小是否为了和某个边界对齐经过了填充。
例如，\ac{PE}文件中的区域(sections)的其实地址总是一个最右边三位是0的十六位数字：0x41000，0x10001000，等等。
原因就是几乎所有的\ac{PE}区域都要和边界值0x1000 (4096)字节对齐而填充。~\footnote{译者语：x86架构下一个页面的大小。}

\subsubsection{精度运算和基数 Multi-precision arithmetic and radix}

\index{RSA}
多精度运算使用大数字，每个大数字的存储可能需要许多个字节。
例如，RSA秘钥，包括公开秘钥和私人秘钥，需要4096比特甚至更多空间来存储。

在\InSqBrackets{\TAOCPvolII, 265}中，我们可以学到这个技巧：当你存储一个多字节的多精度数字，
该数字可以表示为一个基数为$2^8=256$的大数字，其中的每位数字对应于一个字节。
同样，如果你把这个多精度数字按照多个32位整型值来存储，其中的每位数字对应于一个32位整形值，
那就可以把这个数字想象成一个基数为$2^{32}$的大数字。

\subsubsection{发音 Pronouncement}

非十进制数字一般顺着每位数字来念：“1-0-0-1-1-..."。
像"十"，"千"等通常不会出现，因为这些发音通常和十进制关联。

\subsubsection{浮点数字 Floating point numbers}

为了区别于整型数字，浮点数字通常加上".0"作为结尾，例如$0.0$，$123.0$等等。


\end{document}
